package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.domain.InvInventoryCheck;
import com.ruoyi.system.domain.InvInventoryWorkOrder;
import com.ruoyi.system.domain.ProductInventory;
import com.ruoyi.system.dto.ExecuteOrUpdateDTO;
import com.ruoyi.system.dto.InvInventoryWorkOrderDTO;
import com.ruoyi.system.mapper.InvInventoryWorkOrderMapper;
import com.ruoyi.system.service.IProductInventoryService;
import com.ruoyi.system.service.InvInventoryCheckService;
import com.ruoyi.system.service.InvInventoryWorkOrderService;
import com.ruoyi.system.util.AbdulEmptyUtils;
import com.ruoyi.system.util.BookingNumberGenerator;
import com.ruoyi.system.util.StoreIdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class InvInventoryWorkOrderServiceImpl extends ServiceImpl<InvInventoryWorkOrderMapper, InvInventoryWorkOrder> implements InvInventoryWorkOrderService {

    @Autowired
    private InvInventoryCheckService checkService;

    @Autowired
    private IProductInventoryService productInventoryService;

    @Autowired
    private StoreIdUtils storeIdUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(InvInventoryWorkOrder order) {
        // 校验必填字段
        if (AbdulEmptyUtils.isEmpty(order.getWarehouseId())) {
            throw new RuntimeException("请选择盘点仓库");
        }
        if (AbdulEmptyUtils.isEmpty(order.getStocktakingName())) {
            throw new RuntimeException("请填写盘点人");
        }
        if (AbdulEmptyUtils.isEmpty(order.getStocktakingTime())) {
            throw new RuntimeException("请填写盘点时间");
        }
        if (AbdulEmptyUtils.isEmpty(order.getInventoryWorkOrderDTOList())) {
            throw new RuntimeException("请填写盘点明细");
        }

        // 生成编号并保存主单据
        order.setStoreId(storeIdUtils.getStoreId());
        order.setInventoryNumber(BookingNumberGenerator.generateBookingNumber());
        this.save(order);
        Long id = order.getId(); // 盘点工单id
        List<InvInventoryWorkOrderDTO> workOrderDTOList = order.getInventoryWorkOrderDTOList();

        // 获取需要盘点的商品ID集合
        Set<Long> productListId = workOrderDTOList.stream()
                .map(InvInventoryWorkOrderDTO::getProductManagementId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (productListId.isEmpty()) {
            throw new RuntimeException("盘点商品ID不能为空");
        }

        // 查询库存信息
        LambdaQueryWrapper<ProductInventory> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ProductInventory::getProductManagementId, productListId);
        wrapper.eq(ProductInventory::getWarehouseId, order.getWarehouseId());
        List<ProductInventory> inventoryList = productInventoryService.list(wrapper);

        if (AbdulEmptyUtils.isEmpty(inventoryList)) {
            throw new RuntimeException("盘点商品ID不存在");
        }

        // 构建库存映射
        Map<Long, Integer> stockMap = inventoryList.stream()
                .collect(Collectors.toMap(
                        ProductInventory::getProductManagementId,
                        ProductInventory::getStockQuantity,
                        (existing, replacement) -> existing
                ));

        // 校验是否所有商品ID都有对应的库存记录
        Set<Long> foundIds = stockMap.keySet();
        if (!foundIds.containsAll(productListId)) {
            Set<Long> missingIds = new HashSet<>(productListId);
            missingIds.removeAll(foundIds);
            throw new RuntimeException("以下商品ID不存在库存记录: " + missingIds);
        }

        // 构造盘点明细
        List<InvInventoryCheck> list = new ArrayList<>();
        for (InvInventoryWorkOrderDTO dto : workOrderDTOList) {
            InvInventoryCheck check = new InvInventoryCheck();
            check.setWorkOrderId(id);
            check.setProductName(dto.getName());
            check.setCategory(dto.getCategory());
            check.setClassification(dto.getClassification());
            check.setUnit(dto.getUnit());
            check.setSpecification(dto.getSpecification());
            check.setInventoryPrice(dto.getInventoryPrice());
            check.setProductManagementId(dto.getProductManagementId());
            check.setInitialStock(stockMap.getOrDefault(dto.getProductManagementId(), 0));
            check.setStoreId(storeIdUtils.getStoreId());
            list.add(check);
        }
        return checkService.saveBatch(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean executeOrUpdate(ExecuteOrUpdateDTO executeOrUpdateDTO) {
        List<InvInventoryCheck> checkList = check(executeOrUpdateDTO);
        InvInventoryWorkOrder workOrder = this.getById(executeOrUpdateDTO.getId());
        if (AbdulEmptyUtils.isEmpty(workOrder)) {
            throw new RuntimeException("盘点工单不存在");
        }
        //新增的盘点工单数据
        List<InvInventoryCheck> saveList = new ArrayList<>();
        //修改的盘点工单数据
        List<InvInventoryCheck> updateList = new ArrayList<>();

        Set<Long> collect = checkList.stream()
                .map(InvInventoryCheck::getId)
                .filter(id -> !AbdulEmptyUtils.isEmpty(id)).collect(Collectors.toSet());
        Map<Long, InvInventoryCheck> map = null;
        if (!AbdulEmptyUtils.isEmpty(collect)) {
            LambdaQueryWrapper<InvInventoryCheck> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.in(InvInventoryCheck::getId, collect);
            List<InvInventoryCheck> list = checkService.list(queryWrapper);
            map = list.stream().collect(Collectors.toMap(InvInventoryCheck::getId, e -> e));
        }
        for (InvInventoryCheck invInventoryCheck : checkList) {
            if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getId())) {
                //新添加的盘点工单
                invInventoryCheck.setWorkOrderId(executeOrUpdateDTO.getId());
                saveCheck(invInventoryCheck, executeOrUpdateDTO.getType());
                invInventoryCheck.setStoreId(storeIdUtils.getStoreId());
                saveList.add(invInventoryCheck);
            } else {
                Long id = invInventoryCheck.getId();
                InvInventoryCheck check = null;
                if (!AbdulEmptyUtils.isEmpty(map)) {
                    check = map.get(id);
                }
                if (AbdulEmptyUtils.isEmpty(check)) {
                    throw new RuntimeException("盘点商品明细不存在，请核实,ID为:[" + id + "]");
                }
                if (!AbdulEmptyUtils.isEmpty(invInventoryCheck.getCheckedQuantity())) {
                    check.setCheckedQuantity(invInventoryCheck.getCheckedQuantity());
                }
                if (!AbdulEmptyUtils.isEmpty(invInventoryCheck.getPeriodChange())) {
                    check.setPeriodChange(invInventoryCheck.getPeriodChange());
                }
                if (!AbdulEmptyUtils.isEmpty(invInventoryCheck.getInventoryVariance())) {
                    if (invInventoryCheck.getInventoryVariance().equals((invInventoryCheck.getCheckedQuantity() - invInventoryCheck.getInitialStock()))) {
                        check.setInventoryVariance(invInventoryCheck.getInventoryVariance());
                    } else {
                        throw new RuntimeException("盈亏数量计算有误，请检查");
                    }
                }
                if (!AbdulEmptyUtils.isEmpty(invInventoryCheck.getVarianceValue())) {
                    if (invInventoryCheck.getVarianceValue().equals(new BigDecimal(invInventoryCheck.getInventoryVariance()).multiply(invInventoryCheck.getInventoryPrice()))) {
                        check.setVarianceValue(invInventoryCheck.getVarianceValue());
                    } else {
                        throw new RuntimeException("盈亏金额计算有误，请检查");
                    }
                }
                if (!AbdulEmptyUtils.isEmpty(invInventoryCheck.getRemark())) {
                    check.setRemark(invInventoryCheck.getRemark());
                }
                updateList.add(check);
                if (executeOrUpdateDTO.getType() == 2) {
                    if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getCheckedQuantity())) {
                        throw new RuntimeException("请填写盘点数量");
                    }
                    if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getInventoryVariance())) {
                        throw new RuntimeException("请填写盈亏数量");
                    }
                    if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getVarianceValue())) {
                        throw new RuntimeException("请填写盈亏金额");
                    }
                }
            }
        }
        if (!AbdulEmptyUtils.isEmpty(saveList)) {
            checkService.saveBatch(saveList);
        }
        if (!AbdulEmptyUtils.isEmpty(updateList)) {
            checkService.updateBatchById(updateList);
        }
        if (executeOrUpdateDTO.getType() == 2) {
            if (workOrder.getIsStatus().equals(1)) {
                workOrder.setIsStatus(2);
                this.updateById(workOrder);
            } else {
                throw new RuntimeException("该盘点工单已执行");
            }
        }
        return true;
    }


    /**
     * 修改参数效验
     */
    public List<InvInventoryCheck> check(ExecuteOrUpdateDTO executeOrUpdateDTO) {
        if (AbdulEmptyUtils.isEmpty(executeOrUpdateDTO.getType())) {
            throw new RuntimeException("请选择操作类型");
        }
        if (AbdulEmptyUtils.isEmpty(executeOrUpdateDTO.getStocktakingTime())) {
            throw new RuntimeException("请填写盘点时间");
        }
        if (AbdulEmptyUtils.isEmpty(executeOrUpdateDTO.getId())) {
            throw new RuntimeException("请选择盘点工单");
        }
        List<InvInventoryCheck> checkList = executeOrUpdateDTO.getCheckList();
        if (AbdulEmptyUtils.isEmpty(checkList)) {
            throw new RuntimeException("请填写盘点明细");
        }
        return checkList;
    }


    /**
     * 新增盘点商品参数效验
     */
    public void saveCheck(InvInventoryCheck invInventoryCheck, Integer type) {
        if (invInventoryCheck.getInitialStock() <= 0) {
            throw new RuntimeException("期初库存不能小于0");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getProductManagementId())) {
            throw new RuntimeException("盘点商品ID不能为空");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getCategory())) {
            throw new RuntimeException("请填写商品类别");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getClassification())) {
            throw new RuntimeException("请填写商品分类");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getUnit())) {
            throw new RuntimeException("请填写单位");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getSpecification())) {
            throw new RuntimeException("请填写规格");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getInventoryPrice())) {
            throw new RuntimeException("请填写库存单价");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getProductName())) {
            throw new RuntimeException("请填写商品名称");
        }
        if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getInitialStock())) {
            throw new RuntimeException("请填写商品期初库存");
        }
        if (type.equals(2)) {
            if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getCheckedQuantity())) {
                throw new RuntimeException("请填写盘点数量");
            }
            if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getInventoryVariance())) {
                throw new RuntimeException("请填写盈亏数量");
            } else if (!invInventoryCheck.getInventoryVariance().equals((invInventoryCheck.getCheckedQuantity() - invInventoryCheck.getInitialStock()))) {
                throw new RuntimeException("盈亏数量计算有误，请检查");
            }
            if (AbdulEmptyUtils.isEmpty(invInventoryCheck.getVarianceValue())) {
                throw new RuntimeException("请填写盈亏金额");
            } else if (!invInventoryCheck.getVarianceValue().equals(new BigDecimal(invInventoryCheck.getInventoryVariance()).multiply(invInventoryCheck.getInventoryPrice()))) {
                throw new RuntimeException("盈亏金额计算有误，请检查");
            }
        }
    }

}
